#pragma once
#include <string>
#include "owned_string.h"

namespace krryn{
namespace data{
	#define TOKENS(OP) \
		OP("", none) \
		OP("T_EOF", eof) \
		OP("T_INTEGER", integer) \
		OP("T_REAL", real) \
		OP("T_STRING", string) \
		OP("T_OPEN_BRACE", open_brace) \
		OP("T_CLOSE_BRACE", close_brace) \
		OP("T_OPEN_SET", open_set) \
		OP("T_CLOSE_SET", close_set)

	#define KEYWORDS(OP) \
		OP("MD5Version", version) \
		OP("commandline", commandline) \
		OP("numJoints", num_joints) \
		OP("numMeshes", num_meshes) \
		OP("numFrames", num_frames) \
		OP("numverts", numverts) \
		OP("numtris", numtris) \
		OP("numweights", numweights) \
		OP("frameRate", frame_rate) \
		OP("numAnimatedComponents", num_animated_components) \
		OP("hierarchy", hierarchy) \
		OP("bounds", bounds) \
		OP("baseframe", baseframe) \
		OP("frame", frame) \
		OP("joints", joints) \
		OP("mesh", mesh) \
		OP("shader", shader) \
		OP("vert", vert) \
		OP("tri", tri) \
		OP("weight", weight)

	#define TAG(OP) \
		TOKENS(OP) \
		KEYWORDS(OP)

	#define LIST_ENUM(key, value) value,
	#define KEYWORDS_VALUES(key, value) m_Keywords.push_back(key);
	#define KEYWORDS_DETERMINE(key, value) else if(a_Value == key) { return make(value, a_Value); }
	#define TO_STRING(key, value) else if(a_Tag == value) { return key; }

	enum md5_tags{
		TAG(LIST_ENUM)
	};

	std::string tag_to_string(md5_tags a_Tag);

	class md5_token_exception{
	public:
		md5_tags m_CurrentTag;
		md5_tags m_ExpectedTag;

		md5_token_exception(md5_tags a_Current, md5_tags a_Expected)
			: m_CurrentTag(a_Current), m_ExpectedTag(a_Expected) {}
	};

	class md5_token{
	public:
		md5_tags m_Tag;
		core::owned_string m_String;

		md5_token() {}
		md5_token(md5_tags a_Tag, core::owned_string a_String) 
			: m_Tag(a_Tag), m_String(a_String) {}

		std::string as_string();
		int as_int();
		float as_float();
	private:
		void expect(md5_tags a_Tag);
	};
}
}